#include "pintos_thread.h"

// Forward declaration. This function is implemented in reaction-runner.c,
// but you needn't care what it does. Just be sure it's called when
// appropriate within reaction_o()/reaction_h().
void make_water();

struct reaction
{
	int numOfH;
	struct lock lock;
	struct condition hReadyToReaction;
	struct condition oReadyToReaction;
};

void reaction_init(struct reaction *reaction)
{
	reaction->numOfH = 0;
	lock_init(&reaction->lock);
	cond_init(&reaction->hReadyToReaction);
	cond_init(&reaction->oReadyToReaction);
}

void reaction_h(struct reaction *reaction)
{
	lock_acquire(&reaction->lock);
	// 获得 H 原子后令其数量 +1
	reaction->numOfH++;
	// 尝试唤醒 O 原子的线程
	cond_signal(&reaction->oReadyToReaction, &reaction->lock);
	cond_wait(&reaction->hReadyToReaction, &reaction->lock);
	lock_release(&reaction->lock);
}

void reaction_o(struct reaction *reaction)
{
	lock_acquire(&reaction->lock);
	// 当可用的 H 原子个数小于 2 时进入等待
	while (reaction->numOfH < 2)
	{
		cond_wait(&reaction->oReadyToReaction, &reaction->lock);
	}
	// 完成反应后使 H 原子个数 -2 并唤醒两个 H 原子线程
	reaction->numOfH -= 2;
	cond_signal(&reaction->hReadyToReaction, &reaction->lock);
	cond_signal(&reaction->hReadyToReaction, &reaction->lock);
	make_water();
	lock_release(&reaction->lock);
}
